home *** CD-ROM | disk | FTP | other *** search
-
- /* standard headers */
- #include <ctype.h>
- #include <stdio.h>
- #include <string.h>
-
- /* system headers */
- #include <Strings.h>
- #include <TextUtils.h>
-
- /* compiler headers */
- #include <A4Stuff.h>
- #include <DropInCompiler.h>
-
- /* project headers */
- #include "ToolFrontEnd.h"
- #include "FullPath.h"
-
-
- pascal OSErr main(ToolFrontEndStatus* status);
- static OSErr ProcessFile(ToolFrontEndStatus* status, const FSSpec* spec,
- Handle hand, long size, Boolean isIncludeFile);
- static OSErr ParseText(ToolFrontEndStatus* status, const char* text);
- static OSErr IncludeFile(ToolFrontEndStatus* status, const char* inclname, Boolean fullSearch);
- static OSErr ReadOneFile(ToolFrontEndStatus* status, const FSSpec* spec,
- Handle hand, long size, Boolean isIncludeFile, Handle* textp);
-
-
-
- pascal OSErr main(ToolFrontEndStatus* status)
- {
- OSErr err;
-
- /* set up global world (68K only) */
- EnterCodeResource();
-
- status->scanStatus = NULL;
-
- err = ProcessFile(status, &status->cpb->sourcefile, status->cpb->sourcehandle,
- status->cpb->sourcehandlesize, false);
-
- /* tear down global world (68K only) */
- ExitCodeResource();
-
- return err;
- }
-
-
- static OSErr ProcessFile(ToolFrontEndStatus* status, const FSSpec* spec,
- Handle hand, long size, Boolean isIncludeFile)
- {
- Handle text;
- OSErr err;
- Byte state;
-
- /* read in the text & cache it */
- err = ReadOneFile(status, spec, hand, size, isIncludeFile, &text);
- if (err != noErr) return err;
-
- /* process the text */
- state = HGetState(text);
- HLock(text);
- err = ParseText(status, *text);
- HSetState(text, state);
-
- /* release the text */
- (void) CWCompFreeIncludeFile(status->cpb, text);
-
- return err;
- }
-
-
- static OSErr ParseText(ToolFrontEndStatus* status, const char* text)
- {
- const char incltok[] = "include";
- size_t incllen = strlen(incltok);
- OSErr err = noErr;
-
- /*
- * Process the source file text.
- *
- * Look for #include statements at the beginning of every line,
- * then open the specified file and process it recursively.
- */
-
- while ((err == noErr) && (*text != '\0'))
- {
- /* at the top of the loop, we're at the beginning of a line */
-
- char c;
-
- /* skip white space (but not carriage returns) */
- while (((c = *text) != '\r') && isspace(c))
- text++;
-
- if (c == '#')
- {
- /* preprocessor directive */
-
- text++;
-
- /* skip white space */
- while (((c = *text) != '\r') && isspace(c))
- text++;
-
- if (strncmp(text, incltok, incllen) == 0)
- {
- char delim = '\0';
-
- /* we have #include */
- text += incllen;
-
- /* skip white space (but not carriage returns) */
- while (((c = *text) != '\r') && isspace(c))
- text++;
-
- if (c == '"')
- delim = '"';
- else if (c == '<')
- delim = '>';
-
- if (delim != '\0')
- {
- /* we have #include "" or #include <> */
-
- const char* start;
- const char* end;
- char inclname[100];
-
- start = ++text;
- end = strchr(start, delim);
-
- if (end != NULL)
- {
- /* we have an #include file name! */
-
- if (end - start >= sizeof(inclname))
- end = start + sizeof(inclname) + 1;
-
- memcpy(inclname, start, end - start);
- inclname[end - start] = '\0';
-
- err = IncludeFile(status, inclname, (delim == '"'));
-
- text = end;
- }
- }
- }
- }
-
- /* skip to end-of-line */
- while ((c = *text) != '\r')
- text++;
-
- if (c == '\r')
- {
- /* start a new line */
-
- text++;
- status->linecount++;
-
- if ((status->linecount == 1) || (status->linecount % 50 == 0))
- {
- /*
- * We don't want to call this for every line,
- * 'cause it will slow down compilation to a crawl.
- */
-
- err = CWCompDisplayLines(status->cpb, status->linecount);
- }
-
- continue;
- }
- }
-
- return err;
- }
-
-
- static OSErr IncludeFile(ToolFrontEndStatus* status, const char* inclname, Boolean fullSearch)
- {
- FSSpec spec;
- Handle hand;
- long size;
- Str255 pname;
- Boolean alreadyincluded;
- OSErr err;
- int i;
-
- // convert C string to pascal
- for (i = 0; inclname[i] != 0 && i < 255; i++)
- pname[i + 1] = inclname[i];
- pname[0] = i;
-
- /* locate the file name using the project's access paths */
- err = CWCompFindIncludeFile(status->cpb, pname, fullSearch, &hand, &size, &spec,
- &alreadyincluded, false);
-
- if (err == noErr && !alreadyincluded)
- {
- // add the folder of this file to the search path argument list
- int i;
- Boolean found = false;
-
- // DebugStr(pname);
-
- for (i = 0; i < status->numFolderPaths; i++)
- {
- // compare the vRefNum and parID
- if (spec.vRefNum == status->folderPaths[i].vRefNum
- && spec.parID == status->folderPaths[i].dirID)
- {
- found = true;
- break;
- }
- }
-
- if (!found)
- {
- // not already in list -- add it
- Handle dirName;
- short dirNameLength;
-
- if (status->numFolderPaths >= MAXFOLDERPATHS)
- {
- // too many folders error -- fat chance!
- CWCompErrorMessage(status->cpb, "Too many include file folders.");
- err = paramErr;
-
- }
-
- // add to list
- if (err == noErr)
- err = GetFullPath(spec.vRefNum, spec.parID, NULL, &dirNameLength, &dirName);
- if (err == noErr)
- {
- status->folderPaths[status->numFolderPaths].path = dirName;
- status->folderPaths[status->numFolderPaths].vRefNum = spec.vRefNum;
- status->folderPaths[status->numFolderPaths].dirID = spec.parID;
- ++status->numFolderPaths;
- }
- }
-
- err = ProcessFile(status, &spec, hand, size, true);
- }
- else if (err == fnfErr)
- {
- err = noErr; // it's not really an error -- and I don't see a CW warning API....
- #if 0
- char errmsg[200];
-
- sprintf(errmsg, "Can't locate file \"%s\".", inclname);
-
- err = CWCompErrorMessage(status->cpb, errmsg);
- #endif
- }
-
- return (err);
- }
-
-
- static OSErr ReadOneFile(ToolFrontEndStatus* status, const FSSpec* spec,
- Handle hand, long size, Boolean isIncludeFile, Handle* textp)
- {
- Boolean textIsCached = false;
- Handle text;
- OSErr err;
-
- if (hand != NULL)
- {
- /*
- * The file is open in the editor. We have to use 'size' to determine the
- * number of characters to read, because the editor may have appended slop
- * bytes to the end of the text.
- *
- * For simplicity's sake, we'll just copy the text into the temporary buffer,
- * just as we do for files we read from disk.
- */
-
- text = NewHandle(size+1);
- if (text == NULL)
- return (memFullErr);
-
- BlockMoveData(*hand, *text, size);
- (*text)[size] = '\0';
- }
- else
- {
- /*
- * The file isn't open in the editor. If this is an include file, then look
- * for it in the include file cache.
- */
-
- if (isIncludeFile && status->cpb->caching_includes)
- {
- err = CWCompGetCachedIncludeFile(status->cpb, spec, &text);
- textIsCached = (err == noErr);
- }
- else
- err = fnfErr;
-
- if (err != noErr)
- {
- /*
- * The file was in the cache, so we'll have to hit the disk.
- */
-
- short refnum;
-
- err = FSpOpenDF(spec, fsRdPerm, &refnum);
- if (err != noErr)
- return (err);
-
- err = GetEOF(refnum, &size);
- if (err != noErr)
- {
- FSClose(refnum);
- return (err);
- }
-
- text = NewHandle(size+1);
- if (text == NULL)
- {
- FSClose(refnum);
- return (err);
- }
-
- HLock(text);
- err = FSRead(refnum, &size, *text);
- FSClose(refnum);
-
- if (err != noErr)
- {
- DisposeHandle(text);
- return (err);
- }
-
- HUnlock(text);
- (*text)[size] = '\0';
- }
- }
-
- /*
- * At this point, 'text' contains a null-terminated version of our source file.
- * If it's an include file that hasn't been cached already, then cache it.
- */
-
- if (isIncludeFile && status->cpb->caching_includes && !textIsCached)
- {
- err = CWCompCacheIncludeFile(status->cpb, spec, text);
- }
-
- *textp = text;
-
- return (noErr);
- }
-